Frontend Forever App
We have a mobile app for you to download and use. And you can unlock many features in the app.
Get it now
Intall Later
Run
HTML
CSS
Javascript
Output
Document
@charset "UTF-8"; @import url(https://fonts.googleapis.com/css?family=Nunito+Sans:300,400,600,700,800); *, :after, :before { box-sizing: border-box; padding: 0; margin: 0; } body{ overflow: hidden; margin: 0; background-color: #aaa; } #handle { position: absolute; top:50%; left:50%; transform: translate(10%, -60%); } #cnv { position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%); background-color: white; }
console.log("Event Fired") import { Clock, MathUtils } from "https://threejs.org/build/three.module.js"; import { SimplexNoise } from "https://threejs.org/examples/jsm/math/SimplexNoise.js"; console.clear(); // load fonts await (async function () { async function loadFont(fontface) { await fontface.load(); document.fonts.add(fontface); } let fonts = [ new FontFace( "Lato", "url(https://fonts.gstatic.com/s/lato/v24/S6u9w4BMUTPHh50XSwiPGQ.woff2) format('woff2')" ) ]; for (let font in fonts) { //console.log(fonts[font]); await loadFont(fonts[font]); } })(); let simplex = new SimplexNoise(); let unitY = (val) => val * 0.01 * cnv.height; let unitX = (val) => val * 0.01 * cnv.height * 0.5; function resize() { cnv.width = cnv.height = window.innerHeight * 0.95; cnv.width *= 0.5; cnv.style.border = `${unitY(1)}px solid #666`; cnv.style.borderRadius = `${unitY(10)}px`; handle.style.width = cnv.width * 0.5 + "px"; handle.style.height = cnv.height * 0.3 + "px"; handle.style.border = `${unitY(10)}px solid #666`; handle.style.borderRadius = `${unitY(15)}px`; } resize(); window.addEventListener("resize", (event) => { resize(); }); let $ = cnv.getContext("2d"); class Bubble { constructor() { this.currX = 0; this.currY = 0; this.x = 0; this.y = 0; this.border = 0.5; this.radius = 0; this.speed = 0; this.color = 60; this.init(); } init() { this.x = 10 + Math.random() * 80; this.y = 30 + Math.random() * 65; let currX = this.x; let currY = this.y; this.currX = currX; this.currY = currY; this.radius = 1 + Math.random() * 1; this.speed = 0.1 + Math.random() * 0.1; } update() { this.currY -= this.speed; if (this.currY <= 10) { this.init(); } } draw() { let a = 1 - MathUtils.smoothstep(this.currY, this.y - 5, this.y); $.strokeStyle = `hsla(${0}, 75%, 100%, ${a})`; $.lineWidth = unitY(this.border); $.beginPath(); $.arc( unitX(this.currX), unitY(this.currY), unitY(this.radius), 0, Math.PI * 2 ); $.stroke(); } } class Bubbles { constructor() { this.bubbles = new Array(50).fill().map((_) => { return new Bubble(); }); console.log(this); } draw() { $.save(); this.bubbles.forEach((b) => { b.update(); b.draw(); }); $.restore(); } } class Beer { constructor() { this.bubbles = new Bubbles(); this.parts = { bottom: [ { x: 0, y: 100 }, { x: 100, y: 100 } ], top: [ { x: 100, y: 20 }, { x: 66, y: 20 }, { x: 33, y: 20 }, { x: 0, y: 20 } ] }; this.mediators = { top: new Array(4).fill().map((_) => { return { x: 0, y: 0 }; }) }; } draw(time) { $.save(); let t = time * 0.25; let multiplier = 0.01; $.fillStyle = "#FAE96F"; let mt = this.mediators.top; mt.forEach((m, idx) => { m.x = this.parts.top[idx].x; m.y = this.parts.top[idx].y; let yShift = simplex.noise3d(m.x * multiplier, m.y * multiplier, t); m.y += yShift * 5; }); $.beginPath(); $.moveTo(unitX(this.parts.bottom[0].x), unitY(this.parts.bottom[0].y)); $.lineTo(unitX(this.parts.bottom[1].x), unitY(this.parts.bottom[1].y)); $.lineTo(unitX(mt[0].x), unitY(mt[0].y)); $.bezierCurveTo( unitX(mt[1].x), unitY(mt[1].y), unitX(mt[2].x), unitY(mt[2].y), unitX(mt[3].x), unitY(mt[3].y) ); $.closePath(); $.fill(); this.bubbles.draw(); $.save(); let textColor = "hsl(0, 25%, 50%)" $.strokeStyle = textColor; $.fillStyle = "transparent"; $.lineWidth = unitY(1); $.font = `${unitY(20)}px Lato`; $.textAlign = "center"; $.textBaseline = "middle"; let text = "JS"; let textX = 50; let textY = 20; let yShiftText = simplex.noise3d(textX, textY, t); $.translate(unitX(textX), unitY(textY + yShiftText * 2)); let rotText = simplex.noise3d(textX + 100, textY + 100, t); $.rotate(rotText * Math.PI * 0.05); $.strokeText(text, 0, 0); //$.fillText(text, 0, 0); $.restore(); $.strokeStyle = "rgba(200, 200, 200, 0.75)"; $.lineCap = "round"; $.lineWidth = unitY(1); $.beginPath(); $.moveTo(unitX(mt[0].x), unitY(mt[0].y)); $.bezierCurveTo( unitX(mt[1].x), unitY(mt[1].y), unitX(mt[2].x), unitY(mt[2].y), unitX(mt[3].x), unitY(mt[3].y) ); $.stroke(); $.restore(); } } class Dial { constructor() { this.step = (Math.PI * 2) / 60; this.radius = 23; this.hands = [ {l: 17, w: 3, c: "#666", val: 0}, //h {l: 19, w: 2, c: "#555", val: 0}, //m {l: 21, w: 1, c: "#444", val: 0} //s ] this.mediators = { hand: [{x:0, y: 0}, {x:0, y: 0}, {x:0, y: 0}, {x:0, y: 0}] } } draw(time) { let t = time * 0.5; let multiplier = 0.05; $.save(); $.translate(unitX(50), unitY(55 + simplex.noise3d(50, 55, t * 0.125) * 10)); $.lineWidth = unitY(0.5); $.strokeStyle = "#444"; // circle formation for (let i = 0; i < 60; i++) { let a = i * this.step; let x = Math.cos(a) * this.radius; let y = Math.sin(a) * this.radius; let isBigger = i % 5 == 0; let xShift = simplex.noise3d(x * multiplier, y * multiplier, t); let yShift = simplex.noise3d( x * multiplier + 100, y * multiplier + 100, t ); $.beginPath(); $.arc( unitY(x + xShift), unitY(y + yShift), unitY(isBigger ? 1 : 0.5), 0, Math.PI * 2 ); $.stroke(); } // hands let hands = this.hands; let date = new Date(); let milliseconds = (date.getMilliseconds() % 1000) / 1000; let seconds = ((date.getSeconds() % 60) + milliseconds) / 60; let minutes = ((date.getMinutes() % 60) + seconds) / 60; let hours = ((date.getHours() % 12) + minutes) / 12; hands[0].val = (-0.5 + hours * 2) * Math.PI; hands[1].val = (-0.5 + minutes * 2) * Math.PI; hands[2].val = (-0.5 + seconds * 2) * Math.PI; let mh = this.mediators.hand; //multiplier *= 2; hands.forEach(hand => { mh.forEach((m, idx) => { m.x = Math.cos(hand.val) * hand.l * idx * (1 / 3); m.y = Math.sin(hand.val) * hand.l * idx * (1 / 3); let xShift = simplex.noise(m.x * multiplier, m.y * multiplier + t, t) * 2; let yShift = simplex.noise(m.x * multiplier + 100, m.y * multiplier + t + 100, t) * 2; m.x += xShift; m.y += yShift; }) $.save(); $.lineWidth = unitY(hand.w); $.lineCap = "round"; $.lineJoin = "round"; $.strokeStyle = hand.c; $.beginPath(); $.moveTo(unitY(mh[0].x), unitY(mh[0].y)); $.bezierCurveTo(unitY(mh[1].x), unitY(mh[1].y), unitY(mh[2].x), unitY(mh[2].y), unitY(mh[3].x), unitY(mh[3].y)); $.stroke(); $.restore(); }) $.restore(); } } let beer = new Beer(); let dial = new Dial(); let clock = new Clock(); draw(); function draw() { requestAnimationFrame(draw); let time = clock.getElapsedTime(); $.fillStyle = "white"; $.fillRect(0, 0, cnv.width, cnv.height); beer.draw(time); dial.draw(time); }